package org.example;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class TcpClient {

    public static Map<Integer,TcpClient> tcpClientMap = new ConcurrentHashMap<>();

    private Thread thread;

    private String dstAddress;

    private SocketChannel dstChannel;

    private LinkedBlockingQueue<Integer> channelQueue;

    private int port;

    public TcpClient(int port) {
        this.port = port;

        SelectRunnable selectRunnable = new SelectRunnable();
        thread = new Thread(selectRunnable);
        thread.start();
    }

    class SelectRunnable implements Runnable{

        @Override
        public void run() {
            try {

                ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
                // 设置为非阻塞模式
                serverSocketChannel.configureBlocking(false);
                // 绑定到本地端口
                serverSocketChannel.socket().bind(new InetSocketAddress(port));
                // 打开 Selector
                Selector selector = Selector.open();
                // 将 Channel 注册到 Selector，监听 OP_ACCEPT 事件
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);


                ByteBuffer buffer = ByteBuffer.allocate(1024*10);

                while (!Thread.interrupted()) {
                    // 等待事件
                    selector.select();

                    // 处理已准备好的事件
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();

                        try {
                            if (key.isConnectable()) {
                                // 完成连接
                                SocketChannel channel = (SocketChannel) key.channel();
                                SocketChannel clientChannel = (SocketChannel)key.attachment();
                                if (channel.isConnectionPending()) {
                                    channel.finishConnect();
                                }
                                //写个端口号过去
                                ByteBuffer allocate = ByteBuffer.allocate(5+4);
                                allocate.put(new byte[]{0});
                                allocate.putInt(port);
                                allocate.putInt(Config.instance.getAppPort());
                                allocate.flip();
                                channel.write(allocate);

                                // 注册读事件到 Selector
                                channel.register(selector, SelectionKey.OP_READ,clientChannel);

                                //注册读事件到 Selector
                                clientChannel.register(selector, SelectionKey.OP_READ,channel);

                            }else if (key.isAcceptable()) {

                                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                                SocketChannel clientChannel = serverChannel.accept();
                                clientChannel.configureBlocking(false);

                                //告诉对方魔兽争霸3需要连接
                                ByteBuffer allocate = ByteBuffer.allocate(5);
                                allocate.put(new byte[]{1});
                                allocate.putInt(Config.instance.getAppPort());
                                byte[] array = allocate.array();

                                ByteBuffer bf = buildBuffer(dstAddress, array, array.length);

                                int write = -1;

                                try {
                                    write = dstChannel.write(bf);
                                }catch (Exception e){
                                    e.printStackTrace();
                                }

                               if(write!=-1){
                                   Integer poll = channelQueue.poll(10, TimeUnit.SECONDS);

                                   if(poll == null){
                                       System.out.println("获取连接失败:超时");
                                   } else if(poll == 3){
                                       System.out.println("获取连接失败");
                                       //连接失败
                                       clientChannel.close();

                                   }else{
                                       //尝试连接服务端
                                       SocketChannel sc = SocketChannel.open();
                                       sc.configureBlocking(false);
                                       sc.connect(new InetSocketAddress(Config.instance.getServerIp(), Config.instance.getServerTcpPort()));
                                       sc.register(selector, SelectionKey.OP_CONNECT,clientChannel);
                                   }
                               }

                            } else if (key.isReadable()) {

                                SocketChannel srcChannel = (SocketChannel) key.channel();
                                SocketChannel dstChannel = (SocketChannel) key.attachment();

                                int len = -1;
                                try {
                                    len = srcChannel.read(buffer);
                                }catch (Exception e){

                                }
                                if (len == -1) {
                                    srcChannel.close();
                                    dstChannel.close();

                                } else if (len > 0) {
                                    buffer.flip();
                                    dstChannel.write(buffer);
                                    buffer.clear();
                                }
                            }
                        }catch(Exception e){
                            e.printStackTrace();
                        }

                        iterator.remove();

                    }
                }

            } catch (Exception e) {
                System.out.println("UdpSelector 线程异常结束:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }


    public void setDstAddress(String dstAddress) {
        this.dstAddress = dstAddress;
    }

    public void setDstChannel(SocketChannel dstChannel) {
        this.dstChannel = dstChannel;
    }

    public void setChannelQueue(LinkedBlockingQueue<Integer> channelQueue) {
        this.channelQueue = channelQueue;
    }

    private ByteBuffer buildBuffer(String inetSocketAddress, byte[] bt, int len) {
        byte[] bByte = inetSocketAddress.getBytes();
        ByteBuffer allocate = ByteBuffer.allocate(4 + 4 + bByte.length + len);
        allocate.putInt(4 + bByte.length + len);
        allocate.putInt(bByte.length);
        allocate.put(bByte);
        allocate.put(bt, 0, len);
        allocate.flip();
        return allocate;
    }
}
